﻿using System;
using System.IO;
using System.Net;
using System.Text;
using Jamhee.Noctiluca.Common;
using Jamhee.Noctiluca.WebServer;
using Jamhee.Noctiluca.LightWiki.PropertyFiles;

namespace Jamhee.Noctiluca.LightWiki.Pages
{
    abstract class TextPageHandler : IPageHandler
    {
        #region Constants

        private const string WIKI_SITE_LOGO = "$(WIKI_SITE_LOGO)";
        private const string WIKI_SITE_NAME = "$(WIKI_SITE_NAME)";
        private const string WIKI_SITE_COPYRIGHT = "$(WIKI_COPYRIGHT)";
        private const string WIKI_NAVIGATOR = "$(WIKI_NAVIGATOR)";

        #endregion


        #region View Doc

        public void ParseDoc(string contentDocPath, HttpListenerContext context, 
            IWebConfiguration webConfig, UrlQueryResult.ActionType actionType)
        {
            LogUtil.PrintInfo("ParseWikiDoc:" + contentDocPath);

            StreamReader sReader = null;
            StreamWriter sWriter = null;
            HttpListenerResponse response = context.Response;
            System.IO.Stream output = response.OutputStream;

            try
            {
                string viewpagePath = AppUtil.GetAbsolutePath(this.GetPageTemplateName(actionType));
                bool parseWikiMarkup = true;
                if (actionType == UrlQueryResult.ActionType.Edit)
                {
                    parseWikiMarkup = false;
                }

                sReader = new StreamReader(viewpagePath, Encoding.Default);
                sWriter = new StreamWriter(output);

                // Obtain a response object.
                response.ContentType = "text/html; charset=UTF-8";
                response.ContentEncoding = Encoding.UTF8;

                string input = null;
                while ((input = sReader.ReadLine()) != null)
                {
                    sWriter.WriteLine(this.AnalyseLine(contentDocPath, input, webConfig, context.Request.Url, parseWikiMarkup));
                }

                sWriter.Flush();

            }
            catch (Exception e)
            {
                LogUtil.PrintError(e.Message);
            }
            finally
            {
                if (sReader != null)
                {
                    sReader.Close();
                }

                if (sWriter != null)
                {
                    sWriter.Close();
                }

                if (output != null)
                {
                    output.Close();
                }
            }
        }

        private string AnalyseLine(string docPath, string line, IWebConfiguration webConfig, Uri url, bool parseWikiMarkup)
        {
            FileInfo fi = new FileInfo(docPath);
            WikiPageInfo pageInfo = new WikiPageInfo(Path.GetFullPath(fi.DirectoryName + "\\" + WikiConstants.WIKI_DOC_INFO));

            string retValue = line;

            retValue = ReplaceSiteVariable(retValue, webConfig, url, docPath);
            retValue = ReplacePageVariable(docPath, retValue, pageInfo, parseWikiMarkup, url);

            return retValue;
        }

        private string ReplaceSiteVariable(string line, IWebConfiguration webConfig, Uri url, string docPath)
        {
            if (webConfig is WikiConfiguration)
            {
                WikiConfiguration wikiWebcfg = (WikiConfiguration)webConfig;
                string sitelogo = wikiWebcfg.GetSiteLogo();
                string sitename = wikiWebcfg.GetSiteName();
                string copyright = wikiWebcfg.GetCopyright();

                // Replace the logo
                if (line.IndexOf(WIKI_SITE_LOGO) >= 0)
                {
                    line = line.Replace(WIKI_SITE_LOGO, sitelogo);
                }

                // Replace the site name
                if (line.IndexOf(WIKI_SITE_COPYRIGHT) >= 0)
                {
                    line = line.Replace(WIKI_SITE_COPYRIGHT, copyright);
                }

                // Replace the site name
                if (line.IndexOf(WIKI_SITE_NAME) >= 0)
                {
                    line = line.Replace(WIKI_SITE_NAME, sitename);
                }

                if (line.IndexOf(WIKI_NAVIGATOR) >= 0)
                {
                    line = line.Replace(WIKI_NAVIGATOR, GetNavigator(url, webConfig));
                }
            }

            return line;
        }

        protected virtual string GetNavigator(Uri url, IWebConfiguration webConfig)
        {
            StringBuilder navigator = new StringBuilder();
            StringBuilder currentUrl = new StringBuilder();
            currentUrl.Append(url.Scheme + "://" + url.Authority);

            for (int i = 0; i < url.Segments.Length; i ++)
            {
                string segment = url.Segments[i];
                currentUrl.Append(segment);

                if (segment.Equals("/"))
                {
                    // The first one
                    navigator.Append("<a href=\"/\">Home</a>");
                }
                else
                {
                    // Subsequent ones
                    navigator.Append("&nbsp;&gt;&nbsp;");

                    Uri newUrl = new Uri(currentUrl.ToString());
                    string[] files = WikiUtils.GetDocument(newUrl, webConfig, WikiUtils.DocType.PageInfo).Split('|');

                    string pageTitle = segment.TrimEnd('/');
                    for (int x = 0; x < files.Length; x ++)
                    {
                        if (File.Exists(files[x]))
                        {
                            // Use the page own title if exists and not empty
                            WikiPageInfo pageInfo = new WikiPageInfo(files[x]);

                            if (pageInfo.GetPageTitle() != null && pageInfo.GetPageTitle().Length > 0)
                            {
                                pageTitle = pageInfo.GetPageTitle();
                            }

                            break;
                        }
                    }

                    if (!this.HyperLinkForCurrentPageInNavigator && i == url.Segments.Length - 1)
                    {
                        // Don't set the hyper link for current page
                        navigator.Append(pageTitle);
                    }
                    else
                    {
                        string link = "";

                        if (url.Segments.Length >= 5 && i == 2)
                        {
                            link += "<a href=\"#\" onclick=\"javascript:document.getElementById('hiddennav').style.display='inline';this.style.display='none'\">...</a><span id=\"hiddennav\" style=\"display:none\">";
                        }

                        link += "<a href=\" " + currentUrl.ToString().TrimEnd('/') + "\">" + pageTitle + "</a>";

                        if (url.Segments.Length >= 5 && url.Segments.Length - i == 3)
                        {
                            link += "</span>";
                        }

                        // To avoid some relative URL problems, we need to remove the '/' character at the end of URL
                        navigator.Append(link);
                    }
                }
            }

            return navigator.ToString();
        }

        protected abstract string ReplacePageVariable(string docPath, string line, WikiPageInfo pageInfo, bool parseWikiMarkup, Uri url);

        protected abstract string GetPageTemplateName(UrlQueryResult.ActionType action);

        protected abstract bool HyperLinkForCurrentPageInNavigator
        {
            get;
        }

        #endregion


        #region Save Doc

        public abstract void Save(string contentDocPath, HttpListenerContext context,
            IWebConfiguration webConfig);

        public abstract void Download(string contentDocPath, HttpListenerContext context,
            IWebConfiguration webConfig);

        public abstract void Delete(string contentDocPath, HttpListenerContext context,
            IWebConfiguration webConfig);

        #endregion
    }
}
